#pragma once

#include "policy_container.h"
#include "trader.h"
#include <thread>
#include <vector>

struct Record 
{
	std::string trading_day;
	std::string time;
	std::string action;
	double price;
	int volume;
	std::string remark;
	Record(const std::string& p1, const std::string& p2, const std::string& p3, double p4, int p5, const std::string& p6)
	{
		trading_day = p1;
		time = p2;
		action = p3;
		price = p4;
		volume = p5;
		remark = p6;
	}
};

struct Pnl 
{
	Record* record1;
	Record* record2;
	double cost;
	double current_pnl;
	double total_pnl;
};

class SimuTrader : public Trader {
public:
	void Buy(const std::string& instrument, double price, int volume, const std::string& remark = "") override
	{
		printf("%s %s, price %lf, volume %d\n", __func__, instrument.c_str(), price, volume);
		records.emplace_back(Record(last_md->trading_day, last_md->update_time, __func__, price, volume, remark));
	}

	void Sell(const std::string& instrument, double price, int volume, const std::string& remark = "") override
	{
		printf("%s %s, price %lf, volume %d\n", __func__, instrument.c_str(), price, volume);
		records.emplace_back(Record(last_md->trading_day, last_md->update_time, __func__, price, volume, remark));
	}

	void Short(const std::string& instrument, double price, int volume, const std::string& remark = "") override
	{
		printf("%s %s, price %lf, volume %d\n", __func__, instrument.c_str(), price, volume);
		records.emplace_back(Record(last_md->trading_day, last_md->update_time, __func__, price, volume, remark));
	}

	void Cover(const std::string& instrument, double price, int volume, const std::string& remark = "") override
	{
		printf("%s %s, price %lf, volume %d\n", __func__, instrument.c_str(), price, volume);
		records.emplace_back(Record(last_md->trading_day, last_md->update_time, __func__, price, volume, remark));
	}

	const MarketData* last_md = nullptr;

	std::vector<Record> records;
};

class Simulator {
public:
	Simulator();
	bool Run();
	void Save();
private:
	void RunTask(const std::string& file_path, const std::string& trading_day);

	void CalculatePnl()
	{
		pnl_list.clear();
		double total_pnl = 0;
		auto& records = trader_->records;
		for (size_t i = 1; i < records.size(); i += 2)
		{
			Pnl pnl;
			pnl.record1 = &records[i - 1];
			pnl.record2 = &records[i];
			pnl.cost = (records[i].price * records[i].volume + records[i - 1].price * records[i - 1].volume) * cost1_ * multiple_;
			pnl.cost += (records[i].volume + records[i - 1].volume) * cost2_;
			if (records[i].action == "Sell") {	
				pnl.current_pnl = (records[i].price * records[i].volume - records[i - 1].price * records[i - 1].volume) * multiple_ - pnl.cost;
			}
			else {
				pnl.current_pnl = -1 * (records[i].price * records[i].volume - records[i - 1].price * records[i - 1].volume) * multiple_ - pnl.cost;
			}
			total_pnl += pnl.current_pnl;
			pnl.total_pnl = total_pnl;
			pnl_list.emplace_back(pnl);
		}
	}
private:
	SimuTrader* trader_ = new SimuTrader();
	PolicyContainer* policy_container_ = nullptr;
	std::vector<Pnl> pnl_list;

	std::thread thread_;
	bool running_ = true;
	using TaskFunc = std::function<void(void)>;

	std::string product_;
	int multiple_ = 0;
	double cost1_ = 0;
	double cost2_ = 0;

	MarketData md_;
};